package TP6;

public enum Evento {

    LLEGADA_CLIENTE() {

        @Override
        public void calcularProximaLlegada(VectorEstado nuevo) {
            Cliente nuevoCliente = new Cliente();
            nuevoCliente.setHoraLlegada(nuevo.getReloj());
            nuevoCliente.setEstado(EstadoCliente.ESPERANDO_ATENCION);
            nuevo.getExpendedor().addCliente(nuevoCliente);
            atenderCliente(nuevo, nuevoCliente);

            calcularProximaLlegadaCliente(nuevo);
        }
    },
    FIN_ATENCION_CLIENTE() {

        @Override
        public void calcularProximaLlegada(VectorEstado nuevo) {

            nuevo.contarPersonasAtendidas();

            if (!nuevo.getExpendedor().consumirGaseosa(nuevo.getGaseosaElegida())) {

                nuevo.contarPersonaSinGaseosaDeseada();
                nuevo.setRndSeVa();
                if (nuevo.getSiSeVa() || !nuevo.getExpendedor().hayAlgunaGaseosa()) {
                    nuevo.setGaseosaAlternativa(null);
                    nuevo.setRndGaseosaAlternativa(1.0);
                    nuevo.setSiSeVa(true);
                    nuevo.contarPersonasQueSeFueron();
                } else {
                    if (nuevo.getExpendedor().hayAlgunaGaseosa()) {
                        nuevo.setRndGaseosaAlternativa();
                        boolean consumio = nuevo.getExpendedor().consumirGaseosa(nuevo.getGaseosaAlternativa());
                        if (!consumio) {
                            nuevo.setGaseosaAlternativa(nuevo.getExpendedor().consumirCualquierGaseosa());
                        }
                    }
                }
            }

            nuevo.getExpendedor().eliminarCliente();
            nuevo.getExpendedor().setEstado(EstadoServidor.LIBRE);
            if (nuevo.getEstadoRepositor() == EstadoRepositor.ESPERANDO) {
                reponer(nuevo);
            } else {
                if (!nuevo.getExpendedor().getClientes().isEmpty()) {
                    atenderCliente(nuevo, nuevo.getExpendedor().getClienteEnCola());
                }
            }
        }
    },
    LLEGADA_REPOSITOR() {

        @Override
        public void calcularProximaLlegada(VectorEstado nuevo) {
            calcularProximaLlegadaRepositor(nuevo);
            if (nuevo.getExpendedor().getEstado() == EstadoServidor.LIBRE) {
                reponer(nuevo);
            }
            if (nuevo.getExpendedor().getEstado() == EstadoServidor.OCUPADO_POR_CLIENTE) {
                nuevo.setEstadoRepositor(EstadoRepositor.ESPERANDO);
            }
        }
    },
    FIN_REPOSICION() {

        @Override
        public void calcularProximaLlegada(VectorEstado nuevo) {
            nuevo.getExpendedor().reponer();
            nuevo.setEstadoRepositor(EstadoRepositor.NO_ESTA);
            nuevo.getExpendedor().setEstado(EstadoServidor.LIBRE);

            if (!nuevo.getExpendedor().getClientes().isEmpty()) {
                atenderCliente(nuevo, nuevo.getExpendedor().getClienteEnCola());
            }
            
        }
    },
    INICIAL() {

        @Override
        public void calcularProximaLlegada(VectorEstado nuevo) {
            nuevo.setReloj(0);
            calcularProximaLlegadaCliente(nuevo);
            calcularProximaLlegadaRepositor(nuevo);
            nuevo.setEstadoRepositor(EstadoRepositor.NO_ESTA);
            nuevo.setFinReposicion(0);

            calcularProximoDiscoLleno(nuevo);


        }
    },
    DISCO_LLENO() {

        @Override
        public void calcularProximaLlegada(VectorEstado nuevo) {
            calcularProximoDiscoLleno(nuevo);
            if (nuevo.getExpendedor().getEstado() == EstadoServidor.OCUPADO_POR_CLIENTE) {
                nuevo.setFinAtencion(nuevo.getFinAtencion() + 2);
            }
            if (nuevo.getExpendedor().getEstado() == EstadoServidor.OCUPADO_POR_REPOSITOR) {
                nuevo.setFinReposicion(nuevo.getFinReposicion() + 2);
            }

            nuevo.getExpendedor().setEstado(EstadoServidor.DISCO_LLENO);

        }
    };

    abstract void calcularProximaLlegada(VectorEstado nuevo);

    private static void calcularProximaLlegadaCliente(VectorEstado nuevo) {
        nuevo.setRndLlegadaCliente();
        double tiempoEntreLLegada = Simulador.calcularLlegadaCliente(nuevo.getRndLlegadaCliente());
        nuevo.setTiempoEntreLlegadasCliente(tiempoEntreLLegada);
        nuevo.setProximaLlegadaCliente(tiempoEntreLLegada + nuevo.getReloj());
    }

    private static void calcularProximaLlegadaRepositor(VectorEstado nuevo) {
        nuevo.setRndLlegadaRepositor();
        double tiempoEntreLlegadas = Simulador.calcularLlegadaRepositor(nuevo.getRndLlegadaRepositor());
        nuevo.setTiempoEntreLlegadasRepositor(tiempoEntreLlegadas);
        nuevo.setProximaLlegadaRepositor(tiempoEntreLlegadas + nuevo.getReloj());
    }

    private static void atenderCliente(VectorEstado nuevo, Cliente nuevoCliente) {
        if (nuevoCliente == null) {
            return;
        }

        if (nuevo.getExpendedor().getEstado() == EstadoServidor.LIBRE) {
            nuevo.getExpendedor().setEstado(EstadoServidor.OCUPADO_POR_CLIENTE);
            nuevoCliente.setEstado(EstadoCliente.SIENDO_ATENDIDO);
            nuevo.setRndFinAtencionCliente();
            double finAtencion = Simulador.calcularAtencionCliente(nuevo.getRndFinAtencionCliente());
            nuevo.setFinAtencion(finAtencion + nuevo.getReloj());

            nuevo.setRndTipoGaseosa();
            boolean habiaStock = nuevo.getExpendedor().hayGaseosa(nuevo.getGaseosaElegida());
            if (!habiaStock) {
                nuevo.setRndSeVa();
                if (nuevo.getSiSeVa()) {
                } else {
                    nuevo.setRndGaseosaAlternativa();
                    nuevo.getGaseosaAlternativa();
                    boolean habiaStockAlternativo = nuevo.getExpendedor().hayGaseosa(nuevo.getGaseosaAlternativa());
                    if (!habiaStockAlternativo) {
                        nuevo.getExpendedor().hayAlgunaGaseosa();
                    }
                }

            }
        }

    }

    private static void reponer(VectorEstado nuevo) {

        nuevo.setEstadoRepositor(EstadoRepositor.REPONIENDO);
        nuevo.getExpendedor().setEstado(EstadoServidor.OCUPADO_POR_REPOSITOR);
        double tiempoReponer = nuevo.getExpendedor().calcularTiempoReponer();
        nuevo.setFinReposicion(tiempoReponer + nuevo.getReloj());

    }

    private static void calcularProximoDiscoLleno(VectorEstado nuevo) {
        nuevo.setRndDiscoLleno();
        double tiempoLlenadoDisco = Simulador.calcularDiscoLleno(nuevo.getPorcentajeDiscoLleno());
        nuevo.setProximoLlenadoDisco(tiempoLlenadoDisco + nuevo.getReloj());


    }
}
